﻿#region Using Statements
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
#endregion

namespace GameBase.Inputs
{
    /// <summary>
    /// Basic functionality needed for menu and gameplay player input management.
    /// </summary>
    public class PlayerInputManager : IPlayerInput
    {
        #region Fields

        InputState input;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the threshold for thumbstick press detection.
        /// </summary>
        public float ThumbStickThreshold
        {
            get;
            set;
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of this class.
        /// </summary>
        /// <param name="input">Basic input management functions.</param>
        public PlayerInputManager(InputState input)
        {
            this.input = input;

            // default threshold value
            ThumbStickThreshold = 0.5f;
        }

        #endregion

        #region Menu Action

        /// <summary>
        /// Checks for a "press start" input action.
        /// </summary>
        /// <param name="playerIndex">Reports which player pressed the specified button.</param>
        /// <returns>Input action performed.</returns>
        public bool IsMenuPressStart(out PlayerIndex playerIndex)
        {
            bool keyboard = input.IsKeyPress(Keys.Enter, true) || input.IsKeyPress(Keys.Space, true);
            bool gamepad = input.IsButtonPress(Buttons.A, out playerIndex, true) ||
                           input.IsButtonPress(Buttons.Start, out playerIndex, true);

            return keyboard || gamepad;
        }

        /// <summary>
        /// Checks for a "select menu item" input action.
        /// </summary>
        /// <param name="playerIndex">Specifies which player to read input from.</param>
        /// <returns>Input action performed.</returns>
        public bool IsMenuSelect(PlayerIndex playerIndex)
        {
            bool keyboard = input.IsKeyPress(Keys.Enter, true) || input.IsKeyPress(Keys.Space, true);
            bool gamepad = input.IsButtonPress(Buttons.A, playerIndex, true) ||
                           input.IsButtonPress(Buttons.Start, playerIndex, true);

            return keyboard || gamepad;
        }

        /// <summary>
        /// Checks for a "dismiss menu" input action.
        /// </summary>
        /// <param name="playerIndex">Specifies which player to read input from.</param>
        /// <returns>Input action performed.</returns>
        public bool IsMenuBack(PlayerIndex playerIndex)
        {
            bool keyboard = input.IsKeyPress(Keys.Escape, true) || input.IsKeyPress(Keys.Back, true);
            bool gamepad = input.IsButtonPress(Buttons.B, playerIndex, true) ||
                           input.IsButtonPress(Buttons.Back, playerIndex, true);

            return keyboard || gamepad;
        }

        /// <summary>
        /// Checks for a "default menu item values" input action.
        /// </summary>
        /// <param name="playerIndex">Specifies which player to read input from.</param>
        /// <returns>Input action performed.</returns>
        public bool IsMenuDefault(PlayerIndex playerIndex)
        {
            bool keyboard = input.IsKeyPress(Keys.R, true);
            bool gamepad = input.IsButtonPress(Buttons.X, playerIndex, true);

            return keyboard || gamepad;
        }

        #endregion

        #region Menu Navigation

        /// <summary>
        /// Checks for a "menu up" input action.
        /// </summary>
        /// <param name="playerIndex">Specifies which player to read input from.</param>
        /// <param name="isToggled">Button press mode. In toggle mode, separate button presses will be detected.</param>
        /// <returns>Input action performed.</returns>
        public bool IsMenuUp(PlayerIndex playerIndex, bool isToggled)
        {
            bool keyboard = input.IsKeyPress(Keys.Up, isToggled) || input.IsKeyPress(Keys.W, isToggled);
            bool dpad = input.IsButtonPress(Buttons.DPadUp, playerIndex, isToggled);
            bool thumbstick = input.IsThumbStickPress(Buttons.LeftThumbstickUp, playerIndex, ThumbStickThreshold, isToggled) ||
                              input.IsThumbStickPress(Buttons.RightThumbstickUp, playerIndex, ThumbStickThreshold, isToggled);

            return keyboard || dpad || thumbstick;
        }

        /// <summary>
        /// Checks for a "menu down" input action.
        /// </summary>
        /// <param name="playerIndex">Specifies which player to read input from.</param>
        /// <param name="isToggled">Button press mode. In toggle mode, separate button presses will be detected.</param>
        /// <returns>Input action performed.</returns>
        public bool IsMenuDown(PlayerIndex playerIndex, bool isToggled)
        {
            bool keyboard = input.IsKeyPress(Keys.Down, isToggled) || input.IsKeyPress(Keys.S, isToggled);
            bool dpad = input.IsButtonPress(Buttons.DPadDown, playerIndex, isToggled);
            bool thumbstick = input.IsThumbStickPress(Buttons.LeftThumbstickDown, playerIndex, ThumbStickThreshold, isToggled) ||
                              input.IsThumbStickPress(Buttons.RightThumbstickDown, playerIndex, ThumbStickThreshold, isToggled);

            return keyboard || dpad || thumbstick;
        }

        /// <summary>
        /// Checks for a "menu left" input action.
        /// </summary>
        /// <param name="playerIndex">Specifies which player to read input from.</param>
        /// <param name="isToggled">Button press mode. In toggle mode, separate button presses will be detected.</param>
        /// <returns>Input action performed.</returns>
        public bool IsMenuLeft(PlayerIndex playerIndex, bool isToggled)
        {
            bool keyboard = input.IsKeyPress(Keys.Left, isToggled) || input.IsKeyPress(Keys.A, isToggled);
            bool dpad = input.IsButtonPress(Buttons.DPadLeft, playerIndex, isToggled);
            bool thumbstick = input.IsThumbStickPress(Buttons.LeftThumbstickLeft, playerIndex, ThumbStickThreshold, isToggled) ||
                              input.IsThumbStickPress(Buttons.RightThumbstickLeft, playerIndex, ThumbStickThreshold, isToggled);

            return keyboard || dpad || thumbstick;
        }

        /// <summary>
        /// Checks for a "menu right" input action.
        /// </summary>
        /// <param name="playerIndex">Specifies which player to read input from.</param>
        /// <param name="isToggled">Button press mode. In toggle mode, separate button presses will be detected.</param>
        /// <returns>Input action performed.</returns>
        public bool IsMenuRight(PlayerIndex playerIndex, bool isToggled)
        {
            bool keyboard = input.IsKeyPress(Keys.Right, isToggled) || input.IsKeyPress(Keys.D, isToggled);
            bool dpad = input.IsButtonPress(Buttons.DPadRight, playerIndex, isToggled);
            bool thumbstick = input.IsThumbStickPress(Buttons.LeftThumbstickRight, playerIndex, ThumbStickThreshold, isToggled) ||
                              input.IsThumbStickPress(Buttons.RightThumbstickRight, playerIndex, ThumbStickThreshold, isToggled);

            return keyboard || dpad || thumbstick;
        }

        #endregion

        #region GamePlay

        /// <summary>
        /// Checks for a "pause game" input action.
        /// </summary>
        /// <param name="playerIndex">Specifies which player to read input from.</param>
        /// <returns>Input action performed.</returns>
        public bool IsPauseGame(PlayerIndex playerIndex)
        {
            bool keyboard = input.IsKeyPress(Keys.Escape, true);
            bool gamepad = input.IsButtonPress(Buttons.Start, playerIndex, true);

            return keyboard || gamepad;
        }

        #endregion
    }
}
